#include "Timer.h"

#include <DS1307RTC.h>

static tmElements_t tempElements;
static String tempString = "00.00.0000T00:00:00"; // cache for buff

void printTwoDigits(uint8_t v, String &str) {
    if (v < 10) {
        str += "0";
    }
    str += v;
}

String *Timer::toString(time_t time, uint8_t format) {
    breakTime(time, tempElements);

    tempString = "";

    if (format == MIN) {
        printTwoDigits(tempElements.Hour, tempString);
        tempString += ":";
        printTwoDigits(tempElements.Minute, tempString);
    } else {
        if (format == DATE || format == DATETIME) {
            printTwoDigits(tempElements.Day, tempString);
            tempString += ".";
            printTwoDigits(tempElements.Month, tempString);
            tempString += ".";
            tempString += tmYearToCalendar(tempElements.Year);
        }
        if (format == DATETIME) {
            tempString += "T";
        }
        if (format == TIME || format == DATETIME) {
            printTwoDigits(tempElements.Hour, tempString);
            tempString += ":";
            printTwoDigits(tempElements.Minute, tempString);
            tempString += ":";
            printTwoDigits(tempElements.Second, tempString);
        }
    }
    return &tempString;
}

Timer::Timer() {
}

const error_t Timer::begin() {
//    if (!RTC.chipPresent()) {
//        return ERROR_TIMER_UNDEF;
//    }
    setSyncProvider(RTC.get);

    timeStatus_t t = timeStatus();
    if (t == timeNotSet) {
        return ERROR_TIMER_STATUS;
    } else if (t == timeNeedsSync) {
        return ERROR_TIMER_OUTDATE;
    }
    return NO_ERROR;
}

const time_t Timer::time() {
    return now();
}

const tick_t Timer::ticks() {
    return millis();
}

error_t Timer::parceTimeToken(String const &request, char const divider, uint8_t &pos, uint8_t &value, int delta) {
    int i;
    if (divider == 0) {
        i = request.length();
    } else {
        i = request.indexOf(divider, (unsigned int) (pos + 1));
    }
    if (i < 0) {
        return ERROR_TIMER_FORMAT;
    }
    value = (uint8_t) (request.substring((unsigned int) pos, (unsigned int) i).toInt() + delta);
    pos = (uint8_t) (i + 1);
    return NO_ERROR;
}

const bool Timer::isSupported(String const &request) {
    return request.startsWith("TIME");
}

const error_t Timer::processCommand(String const &request, String &response) {
    if (request.equals("TIME?")) { // only command
        response = *toString(now(), DATETIME);
    } else if (request.startsWith("TIME=")) {
        error_t err;
        uint8_t pos = 5; // TIME=

        tmElements_t t;
        if ((err = parceTimeToken(request, '.', pos, t.Day, 0)) != NO_ERROR) {
            return err;
        }
        if ((err = parceTimeToken(request, '.', pos, t.Month, 0)) != NO_ERROR) {
            return err;
        }
        if ((err = parceTimeToken(request, 'T', pos, t.Year, -1970)) != NO_ERROR) {
            return err;
        }
        if ((err = parceTimeToken(request, ':', pos, t.Hour, 0)) != NO_ERROR) {
            return err;
        }
        if ((err = parceTimeToken(request, ':', pos, t.Minute, 0)) != NO_ERROR) {
            return err;
        }
        if ((err = parceTimeToken(request, 0, pos, t.Second, 0)) != NO_ERROR) {
            return err;
        }

        const time_t i = makeTime(t);
        RTC.set(i);
        setTime(i);

        response = *toString(time(), DATETIME);
    }
    return NO_ERROR;
}

